package niu.toy.spring.ioc.impl;

import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import niu.toy.spring.ioc.BeanFactory;
import niu.toy.spring.ioc.annotation.Autowired;
import niu.toy.spring.ioc.annotation.Bean;
import niu.toy.spring.ioc.annotation.Configuration;
import niu.toy.spring.ioc.annotation.Service;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultListableBeanFactory implements BeanFactory {

    private static final Map<Class<?>, Object> beanMap = new ConcurrentHashMap<Class<?>, Object>(256);

    private Set<String> basePackages=  new LinkedHashSet<>(3);


    private void loadClass(){
        try {
            Set<Class<?>> classList = new LinkedHashSet<>(3);
            for(String basePackage:basePackages){
                classList.addAll(ClassUtil.scanPackage(basePackage));
            }
            for (Class<?> cls : classList) {
                if (cls.isAnnotationPresent(Bean.class) || cls.isAnnotationPresent(Service.class) ) {
                    // 创建 Bean 实例
                    Object beanInstance = cls.newInstance();
                    // bean 注册
                    Class<?>[] clsArray= cls.getInterfaces();
                    if(clsArray!=null&&clsArray.length>0)
                        for( Class<?> clsSuper:clsArray){//优先使用接口注册bean
                            beanMap.put(clsSuper, beanInstance);
                        }
                    else{
                        beanMap.put(cls, beanInstance);
                    }
                } else if (cls.isAnnotationPresent(Configuration.class)){
                    Object beanInstance = cls.newInstance();
                    beanMap.put(cls, beanInstance);
                    List<Method> methodList=ReflectUtil.getPublicMethods(cls, new Filter<Method>() {
                        @Override
                        public boolean accept(Method method) {
                            return method.isAnnotationPresent(Bean.class);
                        }
                    });
                    for(Method m:methodList){
                        Object bean=m.invoke(beanInstance);
                        beanMap.put(m.getReturnType(), bean);
                    }

                }
            }
        }catch (Throwable e){
            e.printStackTrace();
        }
    }
    private void populateBean(){
            if(!beanMap.isEmpty()){
                for(Map.Entry<Class<?>, Object> entry:beanMap.entrySet()){
                    Class<?> beanClass=entry.getKey();
                    Object   beanInstance=entry.getValue();
                    Field[]  beanFields=beanClass.getDeclaredFields();
                    if(beanFields!=null&&beanFields.length>0){
                        for(Field beanField:beanFields){
                            if(beanField.isAnnotationPresent(Autowired.class)){
                                Object beanFieldInstance=beanMap.get(beanField.getType());
                                if(beanFieldInstance!=null)
                                    ReflectUtil.setFieldValue(beanInstance,beanField,beanFieldInstance);
                            }
                        }
                    }
                }
            }
    }
    public DefaultListableBeanFactory(String basePackage){
        basePackages.add(basePackage);
        loadClass();
        populateBean();
    }
    public  <T> T getBean(Class<T> cls) {
        if (!beanMap.containsKey(cls)) {
            throw new RuntimeException("无法根据类名获取实例！" + cls);
        }
        return (T) beanMap.get(cls);
    }

    /**
     * 设置 Bean 实例
     */
    public  void setBean(Class<?> cls, Object obj) {
        beanMap.put(cls, obj);
    }

    public  Map<Class<?>, Object> getBeanMap() {
        return beanMap;
    }

    public Set<String> getBasePackages(){return basePackages;}
}
